package ru.ifmo.network;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author avhaliullin
 */
public class DownloadView extends JPanel {
    private final Downloader downloader;
    private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    private final JProgressBar progressBar = new JProgressBar(0, 100);
    private final JLabel textInfo = new JLabel();
    private final JButton abort = new JButton("Abort");
    private final JButton close = new JButton("Close");
    private boolean destinationKnown = false;

    private void setTitle(String title) {
        setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder(title),
                BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        setToolTipText(title);
    }

    private static final String DOUBLE_PLACEHOLDER = "%.2f";

    private String formatSpeed(double speed) {
        if (speed < 103) {
            return String.format(DOUBLE_PLACEHOLDER + " Byte/s", speed);
        }
        if (speed < 1024 * 103) {
            return String.format(DOUBLE_PLACEHOLDER + " KB/s", speed / 1024);
        }
        return String.format(DOUBLE_PLACEHOLDER + " MB/s", speed / (1024 * 1024));

    }

    private String formatSize(long downloaded) {
        long size = downloader.totalSize();
        if (size < 103) {
            return String.format(DOUBLE_PLACEHOLDER + "/" + DOUBLE_PLACEHOLDER + " Bytes", 1.0 * downloaded, 1.0 * size);
        }
        if (size < 1024 * 103) {
            return String.format(DOUBLE_PLACEHOLDER + "/" + DOUBLE_PLACEHOLDER + " KB", downloaded * 1.0 / 1024, size * 1.0 / 1024);
        }
        return String.format(DOUBLE_PLACEHOLDER + "/" + DOUBLE_PLACEHOLDER + " MB", downloaded * 1.0 / (1024 * 1024), size * 1.0 / (1024 * 1024));

    }

    private void done() {
        executor.shutdown();
        abort.setEnabled(false);
    }

    private void updateInfo(final long downloaded, final long downloadedNow, final long timeRangeMs) {
        SwingUtils.invokeLaterIfNotEDT(new Runnable() {
            public void run() {
                if (!destinationKnown && downloader.getDestination() != null) {
                    setTitle("FROM " + downloader.getHostName() + " : " + downloader.getSourceFileName() + " TO " +
                            downloader.getDestination().getAbsolutePath());
                }

                if (downloaded == downloader.totalSize()) {
                    textInfo.setText("Finished (" + formatSize(downloaded) + ")");
                    progressBar.setValue(100);
                    done();
                    return;
                }

                if (downloader.fileExists()) {
                    textInfo.setText("File exists");
                    done();
                    return;
                }

                if (downloader.getException() != null) {
                    textInfo.setText("Error: " + downloader.getException().getMessage());
                    done();
                    return;
                }

                if (downloader.isCancelled()) {
                    textInfo.setText("Aborted");
                    done();
                    return;
                }

                int percent = (int) ((100.0 * downloaded) / downloader.totalSize());
                progressBar.setValue(percent);
                double speed = 1000 * downloadedNow / timeRangeMs;

                textInfo.setText("Downloaded " + percent + "% (" + formatSize(downloaded) +
                        "). Speed: " + formatSpeed(speed));

            }
        });
    }

    public DownloadView(final Downloader downloader) {
        this.downloader = downloader;
        setTitle("From " + downloader.getHostName() + " : " + downloader.getSourceFileName());

        executor.scheduleWithFixedDelay(new Runnable() {
            private long lastDownloaded = 0;
            private long lastCall = 0;

            public void run() {
                long newDownloaded = downloader.downloaded();
                long downloadedNow = newDownloaded - lastDownloaded;

                long timeNow = System.currentTimeMillis();
                long timeRange = timeNow - lastCall;

                lastDownloaded = newDownloaded;
                lastCall = timeNow;

                if (timeNow != timeRange) {
                    updateInfo(newDownloaded, downloadedNow, timeRange);
                }
            }
        }, 1, 1, TimeUnit.SECONDS);
        abort.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                abort.setEnabled(false);
                downloader.cancel();
            }
        });
        close.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
                getParent().remove(DownloadView.this);
            }
        });
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        add(SwingUtils.getBox(true, progressBar, textInfo));

        add(SwingUtils.getBox(true, abort, close));
    }
}
